package com.recruit.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.recruit.common.mybatis.Page;
import com.recruit.common.util.PageUtil;
import com.recruit.common.util.SingleUtil;
import com.recruit.dto.position.CreateOrUpdatePositionDTO;
import com.recruit.model.CompanyDO;
import com.recruit.model.NotifyDO;
import com.recruit.model.PositionDO;
import com.recruit.model.result.PositionResultDO;
import com.recruit.service.CompanyService;
import com.recruit.service.NotifyService;
import com.recruit.service.PositionService;
import com.recruit.vo.CreatedVO;
import com.recruit.vo.DeletedVO;
import com.recruit.vo.PageResponseVO;
import com.recruit.vo.UpdatedVO;
import io.github.talelin.autoconfigure.exception.NotFoundException;
import io.github.talelin.core.annotation.GroupRequired;
import io.github.talelin.core.annotation.Logger;
import io.github.talelin.core.annotation.PermissionMeta;
import io.github.talelin.core.annotation.PermissionModule;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Positive;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * @author DHF
 */
@RestController
@RequestMapping("/recruit/position")
@PermissionModule(value = "职位")
@Api(tags = "职位相关接口")
public class PositionController {

    @Resource
    private PositionService positionService;

    @Resource
    private CompanyService companyService;

    @Resource
    private NotifyService notifyService;

    /**
     * 添加职位
     *
     * @return
     */
    @Logger(template = "发布职位")
    @PostMapping("")
    @GroupRequired
    @PermissionMeta(value = "发布职位")
    @ApiOperation(value = "发布职位")
    public CreatedVO create(
            @ApiParam(value = "创建职位实体", required = true)
            @RequestBody @Validated CreateOrUpdatePositionDTO validator) {
        positionService.createPosition(validator);
        // 职位发布成功后，通知对应的观察者
        // 1. 获取到发布的职位所属的公司外文名
        CompanyDO company = companyService.getById(validator.getCompanyId());
        String foreignName = company.getForeignName();
        // 判断全局map中是否存在对应的被观察者类
        if (SingleUtil.map.containsKey(foreignName)) {
            // 2. 通知所有观察者发布职位了
            SingleUtil.map.get(foreignName).setState(1);
            SingleUtil.map.get(foreignName).setPositionName(validator.getTitle());
            SingleUtil.map.get(foreignName).notifyObservers();
            // 3. 将工具类SingleUtil中的全局messageMap中的数据一一存放到通知表notify中
            Set<String> set = SingleUtil.messageMap.keySet();
            for (String key : set) {
                NotifyDO notifyDO = new NotifyDO();
                notifyDO.setUserName(key);
                notifyDO.setContent(SingleUtil.messageMap.get(key));
                notifyService.create(notifyDO);
            }
            // 4. 清空全局messageMap中的数据
            SingleUtil.messageMap.clear();
        }
        return new CreatedVO(2100);
    }

    /**
     * 根据id更新职位信息
     *
     * @param id
     * @param validator
     * @return
     */
    @Logger(template = "更新职位信息")
    @PutMapping("/{id}")
    @GroupRequired
    @PermissionMeta(value = "更新职位")
    @ApiOperation(value = "更新职位")
    public UpdatedVO updatePosition(
            @ApiParam(value = "职位id", required = true)
            @PathVariable @Positive(message = "{id.positive}") Integer id,
            @ApiParam(value = "修改职位实体", required = true)
            @RequestBody @Validated CreateOrUpdatePositionDTO validator) {
        QueryWrapper<PositionDO> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id);
        PositionDO positionDO = positionService.getOne(wrapper);
        if (positionDO == null) {
            throw new NotFoundException(41000);
        }
        positionService.updatePosition(positionDO, validator);
        return new UpdatedVO(2200);
    }

    /**
     * 根据id更新公司状态state（职位审核
     *
     * @param id
     * @param state
     * @return
     */
    @PutMapping("/state/{id}")
    @GroupRequired
    @PermissionMeta(value = "更新职位状态")
    @ApiOperation(value = "更新职位状态")
    public UpdatedVO update(
            @ApiParam(value = "职位id", required = true)
            @PathVariable @Positive(message = "{id.positive}") Integer id,
            @ApiParam(value = "职位状态", required = true)
            @RequestParam Integer state) {
        QueryWrapper<PositionDO> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id);
        PositionDO positionDO = positionService.getOne(wrapper);
        if (positionDO == null) {
            throw new NotFoundException(41000);
        }
        positionService.updateState(id, state);
        return new UpdatedVO(4000);
    }

    /**
     * 更新职位浏览量
     *
     * @param id
     * @return
     */
    @PutMapping("/hits/{id}")
    @ApiOperation(value = "更新职位浏览量")
    public UpdatedVO updateHits(
            @ApiParam(value = "职位id", required = true)
            @PathVariable @Positive(message = "{id.positive}") Integer id) {
        QueryWrapper<PositionDO> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id);
        PositionDO positionDO = positionService.getOne(wrapper);
        if (positionDO == null) {
            throw new NotFoundException(41000);
        }
        positionService.updateHits(id);
        return new UpdatedVO(4100);
    }

    /**
     * 根据id删除职位
     *
     * @param id
     * @return
     */
    @Logger(template = "删除职位")
    @DeleteMapping("/{id}")
    @GroupRequired
    @PermissionMeta(value = "下架职位")
    @ApiOperation(value = "下架职位")
    public DeletedVO delete(
            @ApiParam(value = "职位id", required = true)
            @PathVariable @Positive(message = "{id.positive}") Integer id) {
        PositionDO positionDO = positionService.findById(id);
        if (positionDO == null) {
            throw new NotFoundException(41000);
        }
        positionService.removeById(id);
        // 职位下架成功后，通知对应的观察者
        // 1. 获取到下架的职位所属的公司外文名
        CompanyDO company = companyService.getById(positionDO.getCompanyId());
        String foreignName = company.getForeignName();
        // 判断全局map中是否存在对应的被观察者类
        if (SingleUtil.map.containsKey(foreignName)) {
            // 2. 通知所有观察者下架职位了
            SingleUtil.map.get(foreignName).setState(0);
            SingleUtil.map.get(foreignName).setPositionName(positionDO.getTitle());
            SingleUtil.map.get(foreignName).notifyObservers();
            // 3. 将工具类SingleUtil中的全局messageMap中的数据一一存放到通知表notify中
            Set<String> set = SingleUtil.messageMap.keySet();
            for (String key : set) {
                NotifyDO notifyDO = new NotifyDO();
                notifyDO.setUserName(key);
                notifyDO.setContent(SingleUtil.messageMap.get(key));
                notifyService.create(notifyDO);
            }
            // 4. 清空全局messageMap中的数据
            SingleUtil.messageMap.clear();
        }
        return new DeletedVO(2000);
    }

    /**
     * 根据职位id查询职位详细信息，包括该职位所属公司的基本信息
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @ApiOperation(value = "根据职位id查询职位详细信息")
    public PositionResultDO get(
            @ApiParam(value = "职位id", required = true)
            @PathVariable(value = "id") @Positive(message = "{id.positive}") Integer id) {
        PositionResultDO positionResultDO = positionService.getById(id);
        if (positionResultDO == null) {
            throw new NotFoundException(41000);
        }
        return positionResultDO;
    }

    /**
     * 根据职位浏览量进行排序，获取前十条数据作为热门职位推荐
     *
     * @return
     */
    @GetMapping("/sort")
    @ApiOperation(value = "获取前十条数据作为热门职位推荐")
    public List<PositionResultDO> sort() {
        List<PositionResultDO> positionResultDOS = positionService.sort();
        if (CollectionUtils.isEmpty(positionResultDOS)) {
            throw new NotFoundException(41000);
        }
        return positionResultDOS;
    }

    /**
     * 根据职位的状态state分页查询职位信息
     *
     * @param count
     * @param page
     * @param state
     * @return
     */
    @GetMapping("/page/{state}")
    @ApiOperation(value = "根据职位的状态state分页查询职位信息")
    public PageResponseVO<PositionDO> page(
            @ApiParam(value = "页面条数", required = false)
            @RequestParam(name = "count", required = false, defaultValue = "10") @Min(value = 1, message = "{page" +
                    ".count.min}") @Max(value = 30, message = "{page.count.max}") Integer count,
            @ApiParam(value = "查询页", required = false)
            @RequestParam(name = "page", required = false, defaultValue = "0") @Min(value = 0, message = "{page" +
                    ".number.min}") Integer page,
            @ApiParam(value = "职位状态", required = true)
            @PathVariable(value = "state") Integer state) {
        // 创建一个封装了请求参数的page对象
        Page<PositionDO> pager = new Page<>(page, count);
        IPage<PositionDO> paging = positionService.getPage(pager, state);
        return PageUtil.build(paging);
    }

    /**
     * 根据hrId分页查询某个HR发布的所有职位信息
     *
     * @param count
     * @param page
     * @param hrId
     * @return
     */
    @GetMapping("/page/hr/{hrId}")
    @GroupRequired
    @PermissionMeta(value = "查看已发布的职位")
    @ApiOperation(value = "查看已发布的职位")
    public PageResponseVO<PositionDO> pageHR(
            @ApiParam(value = "页面条数", required = false)
            @RequestParam(name = "count", required = false, defaultValue = "10") @Min(value = 1, message = "{page" +
                    ".count.min}") @Max(value = 30, message = "{page.count.max}") Integer count,
            @ApiParam(value = "查询页", required = false)
            @RequestParam(name = "page", required = false, defaultValue = "0") @Min(value = 0, message = "{page" +
                    ".number.min}") Integer page,
            @ApiParam(value = "hrId", required = true)
            @PathVariable(value = "hrId") Integer hrId) {
        Page<PositionDO> pager = new Page<>(page, count);
        QueryWrapper<PositionDO> wrapper = new QueryWrapper<>();
        wrapper.eq("hr_id", hrId);
        IPage<PositionDO> paging = positionService.getBaseMapper().selectPage(pager, wrapper);
        return PageUtil.build(paging);
    }

    /**
     * 根据职位名称模糊查询职位列表
     *
     * @param count
     * @param page
     * @param keyword
     * @return
     */
    @GetMapping("/page/keyword")
    @ApiOperation(value = "根据职位名称模糊查询职位列表")
    public PageResponseVO<PositionResultDO> pageKeyword(
            @ApiParam(value = "页面条数", required = false)
            @RequestParam(name = "count", required = false, defaultValue = "10") @Min(value = 1, message = "{page" +
                    ".count.min}") @Max(value = 30, message = "{page.count.max}") Integer count,
            @ApiParam(value = "查询页", required = false)
            @RequestParam(name = "page", required = false, defaultValue = "0") @Min(value = 0, message = "{page" +
                    ".number.min}") Integer page,
            @ApiParam(value = "关键词", required = true)
            @RequestParam String keyword) {
        Page<PositionResultDO> pager = new Page<>(page, count);
        // 获取封装有结果集的分页对象
        IPage<PositionResultDO> paging = positionService.getPageByKeyword(pager, keyword);
        return PageUtil.build(paging);
    }

    /**
     * todo-通过分类、公司、名称模糊查询职位列表
     * 通过type来区别分类（2、公司（1、名称（3
     *
     * @param count
     * @param page
     * @param keyword
     * @param type
     * @return
     */
    @GetMapping("/page/keywordAndType")
    @ApiOperation(value = "通过type来区别分类--职位列表查看")
    public PageResponseVO<PositionResultDO> pageKeywordType(
            @ApiParam(value = "页面条数", required = false)
            @RequestParam(name = "count", required = false, defaultValue = "10") @Min(value = 1, message = "{page" +
                    ".count.min}") @Max(value = 30, message = "{page.count.max}") Integer count,
            @ApiParam(value = "查询页", required = false)
            @RequestParam(name = "page", required = false, defaultValue = "0") @Min(value = 0, message = "{page" +
                    ".number.min}") Integer page,
            @ApiParam(value = "关键词", required = true)
            @RequestParam String keyword,
            @ApiParam(value = "查询分类标识", required = true)
            @RequestParam Integer type) {
        Page<PositionResultDO> pager = new Page<>(page, count);
        // 获取封装有结果集的分页对象
        IPage<PositionResultDO> paging = positionService.getPageByKeywordAndType(pager, keyword, type);
        return PageUtil.build(paging);
    }
}
